#include "appl_thread.h"
#include "socket.h"
#include "user.h"
#include "group.h"
#include "window.h"

#include <string.h>
#include <stdio.h>
extern struct user self;

sem_t sem_Goto, sem_Send, sem_G_Send;
sem_t sem_User_Init, sem_User_Exit, sem_User_Hello;

int threads_num = 9;

int Sems_Init()
{
    int ret = sem_init(&sem_Goto, 0, 1);
    ret |= sem_init(&sem_Send, 0, 0);
    ret |= sem_init(&sem_G_Send, 0, 0);
    ret |= sem_init(&sem_User_Init, 0, 0);
    ret |= sem_init(&sem_User_Exit, 0, 0);
    ret |= sem_init(&sem_User_Hello, 0, 0);

    if (ret != 0)
    {
        perror("sem_init");
        return -1;
    }
    return ret;
}

struct sockaddr_in dst_addr;

s_mapTh2Hnd g_mapTh2Hnd[] = {

    {1, 0, Thread_Goto, .arg = NULL},
    {1, 0, Thread_Recv, .arg = &user_socket},
    {1, 0, Thread_Send, .arg = &user_socket},

    {1, 0, G_Thread_Recv, &grp_socket},
    {1, 0, G_Thread_Send, &user_socket},

    {1, 0, S_Thread_Recv, &sys_socket},
    {1, 0, S_Thread_User_Exit_Notify, &user_socket},
    {1, 0, S_Thread_User_Init_Notify, &user_socket},
    {1, 0, S_Thread_User_Hello_Notify, &user_socket}

};

//获取接收端的ip和端口
void *Thread_Goto(void *arg)
{
    int dst_port = 0;                           //目的端口号
    char dst[] = {0};                           //目的用户
    dst_addr.sin_addr.s_addr = inet_addr(g_ip); //设置接收方IP
    dst_addr.sin_family = AF_INET;              //使用IPv4协议

    sleep(1);

    while (1)
    {
        sem_wait(&sem_Goto);

        printf("1. talk to someone\n");
        printf("2. speak to everyone\n");
        printf("3. exit\n");

        int opt = 0;
        scanf("%d", &opt);
        getchar();

        switch (opt)
        {
        // case 1:
        //     PrintUserTable();
        //     sem_post(&sem_Goto);
        //     break;
        // case 2:
        //     PrintGroupTable();
        //     sem_post(&sem_Goto);
        //     break;
        case 1:
            PrintUserTable();
            printf("enter someone's uid:\n");
            scanf("%s", dst); //输入接收者
            getchar();;
            struct user *u = User_QueryByPort(atoi(dst));
            if (u == NULL)
            {
                printf("用户不存在\n");
                sem_post(&sem_Goto);
                break;
            }
            dst_addr.sin_port = htons(u->port); //设置接收方端口号
            sem_post(&sem_Send);
            break;
        case 2:
            sem_post(&sem_G_Send);
            break;
        // case 5:
        //     PrintGroupTable();
        //     printf("enter a group number:\n");
        //     sem_post(&sem_Goto);
        //     break;
        // case 6:
        //     sem_post(&sem_Goto);
        //     break;
            // printf("enter the group name:\n");
            // char gname[64];
            // scanf("%s", gname);
            // CreateGroup(&self, gname);
        default:
            sem_post(&sem_User_Exit);
            break;
        }
        opt = 0;
        memset(dst, 0, sizeof(dst));
    }
}

//发送线程所要执行的函数 发送消息
void *Thread_Send(void *arg)
{
    int *socket_fd = (int *)arg; //通信的socket
    char msg[1024] = {0};        //消息缓冲区

    //循环发送消息
    while (1)
    {
        sem_wait(&sem_Send);

        printf("发送内容：\n");
        // scanf("%s", msg);
        gets(msg);
        if (strcmp(msg, "exit") == 0)
        {
            // 锁自己 打开GetDst
            sem_post(&sem_Goto);
            continue;
        }

        sendto(*socket_fd, msg, strlen(msg), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));
        sem_post(&sem_Send);
    }
}

void *G_Thread_Send(void *arg)
{
    int *socket_fd = (int *)arg; //通信的socket
    char msg[1024] = {0};        //消息缓冲区

    //循环发送消息
    while (1)
    {
        sem_wait(&sem_G_Send);

        printf("发送内容：\n");
        // scanf("%s", msg);
        gets(msg);
        if (strcmp(msg, "exit") == 0)
        {
            // 锁自己 打开GetDst
            sem_post(&sem_Goto);
            continue;
        }

        dst_addr.sin_port = htons(10000); //广播端
        sendto(*socket_fd, msg, strlen(msg), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));

        sem_post(&sem_G_Send);
    }
}

//接收线程所要执行的函数 接收消息
void *Thread_Recv(void *arg)
{
    int ret = 0;
    int *socket_fd = (int *)arg;       //通信的socket
    struct sockaddr_in src_addr = {0}; //用来存放对方(信息的发送方)的IP地址信息
    int len = sizeof(src_addr);        //地址信息的大小
    char msg[1024] = {0};              //消息缓冲区

    //循环接收客户发送过来的数据
    while (1)
    {
        ret = recvfrom(*socket_fd, msg, sizeof(msg), 0, (struct sockaddr *)&src_addr, &len);
        if (ret == -1)
        {
            break;
        }
        const struct user *src_user = User_QueryByPort(ntohs(src_addr.sin_port));
        if (src_user != NULL)
        {
            printf("[%s:]", src_user->name);
            printf("msg=%s\n", msg);
        }

        memset(msg, 0, sizeof(msg)); //清空存留消息
    }
    //关闭通信socket
    close(*socket_fd);
    return NULL;
}

void *G_Thread_Recv(void *arg)
{
    int *socket_fd = (int *)arg;       //通信的socket
    struct sockaddr_in src_addr = {0}; //定义一个缓冲区 存放对方的IP地址信息
    int len = sizeof(src_addr);
    char buf[1024] = {0}; //消息缓冲区

    //4 接收消息
    while (1)
    {
        recvfrom(*socket_fd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &len);

        struct user *u = User_QueryByPort(ntohs(src_addr.sin_port));
        printf("[broadcast from :%s uid:%d]:", u->name, u->port); //打印消息发送者的IP信息
        printf("%s\n", buf);
        bzero(buf, sizeof(buf)); //清空接收到的消息，避免影响下次接收
    }
}

void *S_Thread_Recv(void *arg)
{

    int *socket_fd = (int *)arg;       //通信的socket
    struct sockaddr_in src_addr = {0}; //定义一个缓冲区 存放对方的IP地址信息
    int len = sizeof(src_addr);
    char buf[1024] = {0}; //消息缓冲区

    sem_post(&sem_User_Init);
    // sem_post(&sem_User_Init);
    //4 接收消息
    while (1)
    {
        recvfrom(*socket_fd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &len);
        struct user *u = User_QueryByPort(ntohs(src_addr.sin_port));
        switch (buf[0])
        {
        case 'h':
            if (u == NULL)
            {
                u = User_Add(ntohs(src_addr.sin_port), buf + 2);
                printf("[user:%s] say hello to you\n", u->name); //打印消息发送者的IP信息
            }
            break;
        case 'i':
            if (u == NULL)
            {
                u = User_Add(ntohs(src_addr.sin_port), buf + 2);
            }
            printf("[user:%s] entered\n", u->name); //打印消息发送者的IP信息
            sem_post(&sem_User_Hello);
            break;
        case 'e':
            printf("[user:%s] quited\n", u->name); //打印消息发送者的IP信息
            User_RemoveByPort(u->port);
            break;
        default:
            break;
        }
        bzero(buf, sizeof(buf)); //清空接收到的消息，避免影响下次接收
    }
}

void *S_Thread_User_Exit_Notify(void *arg)
{
    sem_wait(&sem_User_Exit);
    int *socket_fd = (int *)arg;

    char msg[64] = {"e "};
    strcat(msg, self.name);

    struct sockaddr_in dst_addr = {0};          //地址信息结构体
    dst_addr.sin_family = AF_INET;              //使用IPv4协议
    dst_addr.sin_port = htons(8000);            //通知端
    dst_addr.sin_addr.s_addr = inet_addr(g_ip); //32位的整形

    sendto(*socket_fd, msg, strlen(msg), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));

    for (int i = 0; i < threads_num; i++)
    {
        g_mapTh2Hnd[i].thread_quit_flag = 1;
    }
    return 0;
}

void *S_Thread_User_Init_Notify(void *arg)
{
    sem_wait(&sem_User_Init);
    sleep(1);

    int *socket_fd = (int *)arg;

    char msg[64] = {"i "};
    strcat(msg, self.name);

    struct sockaddr_in dst_addr = {0};          //地址信息结构体
    dst_addr.sin_family = AF_INET;              //使用IPv4协议
    dst_addr.sin_port = htons(8000);            //通知端
    dst_addr.sin_addr.s_addr = inet_addr(g_ip); //32位的整形

    sendto(*socket_fd, msg, strlen(msg), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));

    return 0;
}

void *S_Thread_User_Hello_Notify(void *arg)
{
    int *socket_fd = (int *)arg;

    char msg[64] = {"h "};
    strcat(msg, self.name);

    struct sockaddr_in dst_addr = {0};          //地址信息结构体
    dst_addr.sin_family = AF_INET;              //使用IPv4协议
    dst_addr.sin_port = htons(8000);            //通知端
    dst_addr.sin_addr.s_addr = inet_addr(g_ip); //32位的整形

    while (1)
    {
        sem_wait(&sem_User_Hello);
        sendto(*socket_fd, msg, strlen(msg), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr));
    }
    return 0;
}

void *show_header()
{
    //获取窗口和client
    struct chat_window *win = &g_win;

    chat_win_create_header(); //新建顶部窗口
    wrefresh(win->header);    //刷新

    int i = 1, j = 1;
    const char *runing = "Welcome to F4 Chat system";

    //循环显示runing
    while (1)
    {
        //获得顶部窗口最大行、列数
        int _y, _x;
        getmaxyx(win->header, _y, _x);
        //清除顶部窗口第y/2行，便于下次显示
        chat_win_clr_lines(win->header, _y / 2, 1);
        //新建顶部窗口
        //win->create_header();
        //显示runing
        chat_win_put_str(win->header, _y / 2, j++, runing);
        //如果到达右边界，从左开始
        if (j >= _x - strlen(runing) - 1)
            j = 1;
        //刷新
        wrefresh(win->header);
        //停留200ms
        usleep(200000);
    }
}

void *show_output_fl()
{
    //获取窗口和client
    struct chat_window *win = &g_win;

    //输出窗口和好友窗口
    chat_win_create_output();
    chat_win_create_friends();
    // flist.clear();

    int _w, _h;
    int i = 1;
    // std::string recv_str;
    // std::string friends;	//好友

    //展示好友的姓名-学校
    // data d;
    // std::string show_str = d.name;
    // show_str += "-";
    // show_str += d.school;
    // friends = show_str;

    while (1)
    {
        usleep(300000); //停留300ms
    }
}

void *show_input()
{
    //获取窗口和client
    struct chat_window *win = &g_win;

    char win_in[64];

    const char* tips = "Please Enter#:";
    const char* over = "Send Over     ";
    while (1)
    {
        chat_win_create_input();
        chat_win_put_str(win->input, 1, 2, tips);
        chat_win_get_str(win->input, win_in);
        chat_win_put_str(win->input, 1, 2, over);

        chat_win_clr_lines(win->input, 1, 1);
        
        chat_win_put_str(win->output, win->output->_cury + 1, 2, win_in);
        wrefresh(win->input);
        usleep(300000);
    }
}
